use crate::common::instance_mgr::{InstanceMgr, Value};
use mongodb::bson::oid::ObjectId;
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::RwLock;
use time_util;

lazy_static::lazy_static! {
    static ref INSTANCE:InstanceMgr<TokenModel>=InstanceMgr::default();
    static ref USER_TOKEN:RwLock<HashMap<String,ObjectId>>=RwLock::new(HashMap::new());
}
pub struct TokenModel {
    token_id: ObjectId,
    user_id: ObjectId,
    create_time: i64,
}

// 过期毫秒
const TOKEN_EXPIRE_MS: i64 = 4 * 60 * 60 * 1000;

impl TokenModel {
    pub fn get_token_id_str(&self) -> String {
        format!("{}{:X}", self.token_id.to_hex(), self.create_time)
    }

    pub fn get_token_id(&self) -> ObjectId {
        self.token_id.clone()
    }

    pub fn get_user_id(&self) -> ObjectId {
        self.user_id.clone()
    }
}

pub fn get_token(token_id: &String) -> Option<Value<TokenModel>> {
    INSTANCE.get(token_id)
}

pub fn generate_token(user_id: ObjectId) -> Value<TokenModel> {
    let token_id = ObjectId::new();
    let create_time = time_util::now_unix();
    let token_model = TokenModel {
        token_id: token_id.clone(),
        user_id: user_id.clone(),
        create_time,
    };

    // 删除老的token
    {
        let old_token = get_user_token(&user_id);
        match old_token {
            Some(val) => {
                INSTANCE.remove(&val.to_hex());
            }
            _ => {}
        }
    }

    let result = INSTANCE.set(&token_model.token_id.to_hex(), token_model);
    USER_TOKEN
        .write()
        .unwrap()
        .insert(user_id.to_hex(), token_id);
    result
}

pub fn remove_token(token_id: ObjectId) -> Option<Value<TokenModel>> {
    INSTANCE.remove(&token_id.to_hex())
}

pub fn check_token(token: &String) -> Result<Option<Value<TokenModel>>, ()> {
    if token.len() <= 24 {
        return Err(());
    }

    let token_id_str = token[..24].to_string();
    let token_id_result = ObjectId::from_str(token_id_str.as_str());
    match token_id_result {
        Ok(_) => {}
        Err(_err) => {
            println!("object id convert err:{:?} {:?}", _err, token_id_str);
            return Err(());
        }
    }

    let create_time_result = i64::from_str_radix(&token[24..], 16);
    let create_time;
    match create_time_result {
        Ok(val) => create_time = val,
        Err(_err) => {
            println!("create_time convert err:{:?} {:?}", _err, &token[24..]);
            return Err(());
        }
    }

    let token_obj = get_token(&token_id_str);
    match token_obj {
        Some(val) => {
            if val.read().unwrap().create_time != create_time {
                return Err(());
            }

            // 检查 是否过期
            if create_time + TOKEN_EXPIRE_MS < time_util::now_unix() {
                return Err(());
            }

            Ok(Some(val))
        }
        None => Ok(None),
    }
}

pub fn get_user_token(user_id: &ObjectId) -> Option<ObjectId> {
    let reader = USER_TOKEN.read().unwrap();
    let old_token = reader.get(&user_id.to_hex());
    match old_token {
        Some(val) => Some(val.clone()),
        _ => None,
    }
}
